﻿
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Nui.Vision;
using WiimoteLib;


namespace Fade
{
    public static class MicrophoneExtensions
    {
        // Provides a simple method to check if a microphone is connected.
        public static bool IsConnected(this Microphone microphone)
        {
            try
            {
                MicrophoneState state = microphone.State;
                return true;
            }
            catch (NoMicrophoneConnectedException)
            {
                return false;
            }
        }
    }


    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Game
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern uint MessageBox(IntPtr hWnd, String text, String caption, uint type);

        // Graphic things
        GraphicsDeviceManager graphics;
        SpriteBatch mBatch;
        SpriteFont gameFont;
        SpriteFont titleFont;
        SpriteFont helpFont;

        Color _mainColor = new Color(62, 165, 231);

        // Ship
        Texture2D t2dShip;
        Texture2D t2dHealthBar;
        Vector2 posShip;
        int maxShipHealth = 100;
        int shipHealth = 100;
        int shipRecovery = 2000; // number of miliseconds, where ship recovers 1 helt point
        int shipRecoveryPassedTime = 0;
        int spaceBottom = 30;
        float ScallingShip = 0.35f;
        float aMoveDist = 5.5f;
        Color[,] textureDataShip; // vor pixel colistion
        Matrix mtrShip;

        // Bomb
        Texture2D t2dMegabomb;
        float scallingMegabomb = 0.05f;
        const int MegaBombBonusScore = 1000;
        int _nextMegaBombBonus = 1000;

        // Enemys
        Texture2D t2dEdemy;
        List<Vector2> posEnemys = new List<Vector2>();
        Vector2 speedEnemy = new Vector2(0, 200);
        Vector2 directionEnemy = new Vector2(0, 1);
        Random rndEnemy = new Random();
        float scallingEnemy = 0.5f;
        int numberOfEnemysMax = 50;
        int chancePerTicForNewEnemy = 5; // in %
        Color[,] textureDataEnemy; // vor pixel colistion
        Matrix mtrEnemy;
        const int HitEnemyScore = 10000;

        // Dead enemies
        Texture2D t2dDeathEnemy;
        List<Vector2> posDeathEnemys = new List<Vector2>();
        float scallingDeathEnemy = 0.5f;
        List<int> remainingTimeDeathEnemys = new List<int>();
        int durationDeathEnemy = 3;

        // Planets
        Texture2D t2dPlanet;
        List<Vector2> posPlanet = new List<Vector2>();
        Vector2 speedPlanet = new Vector2(0, 110);
        Vector2 directionPlanet = new Vector2(0, 1);
        Random rndPlanet = new Random();
        List<float>scallingPlanet = new List<float>();
        double scallingPlanetMax = 0.475;
        double scallingPlanetMin = 0.1;
        int numberOfPlanetMax = 15;
        int chancePerTicForNewPlanet = 2; // in %
        Color[,] textureDataPlanet; // vor pixel colistion
        Matrix mtrPlanet;

        // Shoots
        Texture2D t2dShoot;
        List<Vector2> posShoot = new List<Vector2>();
        Vector2 speedShoot = new Vector2(2, 2);
        List<Vector2> directionShoot = new List<Vector2>();
        float scallingShoot = 0.15f;
        Color[,]textureDataShoot; // for pixel collision
        Matrix mtrShoot;
        MouseState previousMouseState = new MouseState();
        MouseState currentMouseState = new MouseState();
        // used in parallele with the mouse
        bool previousWiimoteState = false;
        bool currentWiimoteState = false;

        // Target
        Texture2D t2dTarget;
        Vector2 posTarget = new Vector2();
        float scallingTarget = 1.0f;
        int targetZoneWidth;
        int targetZoneHeight;

        // Screen title
        Texture2D t2dGameTitle;
        Vector2 posGameTitle = new Vector2();
        private Texture2D t2dPlayText;
        private Texture2D t2dPlayTextRed;
        Vector2 posPlayText = new Vector2();
        private Texture2D t2dHelpText;
        private Texture2D t2dHelpTextRed;
        Vector2 posHelpText = new Vector2();
        private Texture2D t2dQuitText;
        private Texture2D t2dQuitTextRed;
        Vector2 posQuitText = new Vector2();
        private Texture2D t2dBackText;
        private Texture2D t2dBackTextRed;
        Vector2 posBackText = new Vector2();
        private Texture2D t2dHelpPicture;

        // Background
        Texture2D t2dBack1;
        Texture2D t2dBack2;
        Vector2 posBack1;
        Vector2 posBack2;
        float scallingBack = 1.0f;
        Vector2 directionBackground = new Vector2(0, 1);
        Vector2 speedBackground = new Vector2(0, 110);

        // Mouse
        Texture2D t2dCursor;
        Vector2 posCursor = new Vector2();
        bool isMouseOverPlayButton = false;
        bool isMouseOverHelpButton = false;
        bool isMouseOverQuitButton = false;
        bool isMouseOverBackButton = false;

        // Wiimote
        Wiimote wm;
        int cntWiimoteRumbling;
        int wiimoteRumblingTime = 30;

        //Sound
        // The most recent microphone samples.
        byte[] micSamples;
        // A circular buffer that we feedback into from micSamples
        byte[] echoBuffer;
        // Tracks the position into the echo buffer.
        int echoBufferPosition = 0;

        // Microphone used for recording.
        Microphone activeMicrophone;
        // Used to communicate the microphone status to the user.
        string microphoneStatus = string.Empty;
        // On big endian systems audio samples need to be swapped because 
        // BinaryReader/BinaryWriter assume little endian.
        bool bigEndian = !BitConverter.IsLittleEndian;
        
        
        float curDetectedSoundVolume = 0.0f;
        float oldDetectedSoundVolume = 0.0f;

        float sensibilityVolume = 20000;
        bool isSensibilityChanging = false;
        bool shouldSensibilityChange = false;
        float maxSensibilityVolume = float.MaxValue;
        float minSensibilityVolume = 5000;

        bool wasSoundShooting = false;
        bool shouldSoundShooting = false;

        // Game & Player
        int _playerScore = 0; // score in milli secondes
        int level = 1;
        double imunPassedTime = 0; // Time passed who indestructible
        double imunMaxTime = 3000; // miliseconds of industricible time
        bool _isPlayerImmune = false; // indicator if is imune against enemies
        enum GAMESTATE { Start_Screen, Play, Death, Calibrate, Help };
        GAMESTATE gameNow = GAMESTATE.Start_Screen;
        private int _MegaBombsNumber;
        private const int MaxMegaBombs = 5;
        private TimeSpan _playerGameTime;
        

        
        // Kinect
        private readonly NuiUserTracker kinectSkeleton;
        private bool useKinect = true;
        Texture2D kinectPsiPose2D;
        Texture2D kinectPsiPoseGreen2D;
        Texture2D kinectPsiPoseRed2D;
        Vector2 kinectPsiPoseVector;
        private const int CalibrationTimeoutSeconds = 30;        // Timeout before the calibration is a failure and the game begins
        private const int CalibrationSucessTimeout = 3;         // Delay between the calibration sucess and the game start
        private DateTime calibrationStart;                      // Start of the calibration attempt
        private DateTime calibrationSuccess;                    // Start of the calibration success (used to evaluate when the game will begin after calibration)
        private bool isKinectCalibrated = false;                // Résultat de la détection d'un utilisateur
        private const int ScreenWidth = 1000;
        private const int KinectWidth = 640;
        private float kinectPixel;
        private const float KinectMultiple = 0.8f;

        // Sounds
        private SoundEffect soundExplosion;
        private SoundEffect soundBlast;
        private SoundEffect soundLevelup;
        /* Disabled because of a high cpu usage */
        private bool _isSoundEffectOn = false;


        //Constructor
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);

            // Kinect detection
            try
            {
                kinectSkeleton = new NuiUserTracker("SamplesConfig.xml");
                kinectSkeleton.UserUpdated += KinectSkeletonUserUpdated;
                Console.WriteLine("Kinect connected !");

            }
            catch (Exception)
            {
                Console.WriteLine("Kinect not present !");
                useKinect = false;
            }

            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            //Change the resolution
            graphics.PreferredBackBufferWidth = ScreenWidth;
            graphics.PreferredBackBufferHeight = 900;
            graphics.IsFullScreen = true;
            graphics.ApplyChanges();

            // Ratio between the kinect resolution and the screen resolution
            kinectPixel = ScreenWidth/KinectWidth+KinectMultiple;

            //this.IsMouseVisible = true;
            // init Target Zone size
            this.targetZoneWidth = this.Window.ClientBounds.Right - this.Window.ClientBounds.Left;
            this.targetZoneHeight = this.Window.ClientBounds.Bottom - this.Window.ClientBounds.Top - 300;

            initWiimote();
            base.Initialize();
        }



        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {

            // Create a new SpriteBatch, which can be used to draw textures.
            mBatch = new SpriteBatch(GraphicsDevice);
            //ContentManager Content = new ContentManager(Services);
            gameFont = Content.Load<SpriteFont>(@"Mono");
            titleFont = Content.Load<SpriteFont>(@"BigMono");
            helpFont = Content.Load<SpriteFont>(@"Mono");

            // Game Title
            t2dGameTitle = Content.Load<Texture2D>("shoot_title") as Texture2D;
            posGameTitle = new Vector2(Window.ClientBounds.Width / 2 - (t2dGameTitle.Width / 2), 50);
            t2dPlayText = Content.Load<Texture2D>("play_text") as Texture2D;
            t2dPlayTextRed = Content.Load<Texture2D>("play_text2") as Texture2D;
            t2dHelpText = Content.Load<Texture2D>("help_text") as Texture2D;
            t2dHelpTextRed = Content.Load<Texture2D>("help_text2") as Texture2D;
            t2dQuitText = Content.Load<Texture2D>("quit_text") as Texture2D;
            t2dQuitTextRed = Content.Load<Texture2D>("quit_text2") as Texture2D;
            t2dBackText = Content.Load<Texture2D>("back_text") as Texture2D;
            t2dBackTextRed = Content.Load<Texture2D>("back_text2") as Texture2D;
            t2dHelpPicture = Content.Load<Texture2D>("help_picture") as Texture2D;

            // Bomb
            t2dMegabomb = Content.Load<Texture2D>("megabomb") as Texture2D;

            // Ship
            t2dShip = Content.Load<Texture2D>("space_ship") as Texture2D;
            t2dHealthBar = Content.Load<Texture2D>("HealthBar") as Texture2D;
            posShip = new Vector2(Window.ClientBounds.Width / 2 - (t2dShip.Width / 2 * ScallingShip), this.Window.ClientBounds.Height - (t2dShip.Height * ScallingShip) - spaceBottom);
            textureDataShip = Utils.TextureTo2DArray(t2dShip);

            // Enemy
            t2dEdemy = Content.Load<Texture2D>("enemy_ship") as Texture2D;
            textureDataEnemy = Utils.TextureTo2DArray(t2dEdemy);

            // DeathEnemy
            t2dDeathEnemy = Content.Load<Texture2D>("enemyDeath") as Texture2D;

            // Planet
            t2dPlanet = Content.Load<Texture2D>("planet") as Texture2D;
            textureDataPlanet = Utils.TextureTo2DArray(t2dPlanet);

            // Shoot
            t2dShoot = Content.Load<Texture2D>("shoot_ball") as Texture2D;
            textureDataShoot = Utils.TextureTo2DArray(t2dShoot);

            // Target
            t2dTarget = Content.Load<Texture2D>("vise3") as Texture2D;

            // Cursor
            t2dCursor = Content.Load<Texture2D>("cursor2") as Texture2D;
            
            // Background
            t2dBack1 = Content.Load<Texture2D>("Background") as Texture2D;
            posBack1 = Vector2.Zero;
            t2dBack2 = Content.Load<Texture2D>("Background") as Texture2D;
            posBack2 = new Vector2(0, -t2dBack2.Height);

            // Kinect Screen
            kinectPsiPose2D = Content.Load<Texture2D>("PsiPose");
            kinectPsiPoseGreen2D = Content.Load<Texture2D>("PsiPoseGreen");
            kinectPsiPoseRed2D = Content.Load<Texture2D>("PsiPoseRed");
            kinectPsiPoseVector = new Vector2(  Window.ClientBounds.Width / 2 - (kinectPsiPose2D.Width / 2),
                                                Window.ClientBounds.Height / 2 - kinectPsiPose2D.Height/2 - spaceBottom);
            

            // Sound output
            /* disable because of a high CPU usage */
            if (_isSoundEffectOn)
            {
                soundExplosion = Content.Load<SoundEffect>("Explosion");
                soundBlast = Content.Load<SoundEffect>("ShootSound");
                soundLevelup = Content.Load<SoundEffect>("Levelup");
            }

            // sound input
            InitializeMicrophone();

            // place target in the middle of the screen
            this.initTarget();
        }


        
        #region Wiimote
        private void initWiimote()
        {
            // create a new instance of the Wiimote
            wm = new Wiimote();

            // setup the event to handle state changes
            wm.WiimoteChanged += wm_WiimoteChanged;

            // setup the event to handle insertion/removal of extensions
            wm.WiimoteExtensionChanged += wm_WiimoteExtensionChanged;

            try
            {
                // connect to the Wiimote
                wm.Connect();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

            // set the report type to return the IR sensor and accelerometer data (buttons always come back)
            wm.SetReportType(InputReport.IRAccel, true);
        }


        void wm_WiimoteExtensionChanged(object sender, WiimoteExtensionChangedEventArgs args)
        {
            if (args.Inserted)
                wm.SetReportType(InputReport.IRExtensionAccel, true);    // return extension data
            else
                wm.SetReportType(InputReport.IRAccel, true);            // back to original mode
        }

        void wm_WiimoteChanged(object sender, WiimoteChangedEventArgs args)
        {
            // current state information
            WiimoteState ws = args.WiimoteState;

            // Check if the user is changing the sound sensibility
            isSensibilityChanging = shouldSensibilityChange;
            shouldSensibilityChange = (ws.ButtonState.Down || ws.ButtonState.Up);

            if (shouldSensibilityChange && !isSensibilityChanging)
            {
                // modify sound sensibility
                if (ws.ButtonState.Down && this.sensibilityVolume > this.minSensibilityVolume)
                {
                    this.sensibilityVolume -= 1000;
                    Console.WriteLine("Sensibility = " + this.sensibilityVolume);
                }
                if (ws.ButtonState.Up && this.sensibilityVolume < this.maxSensibilityVolume)
                {
                    this.sensibilityVolume += 1000;
                    Console.WriteLine("Sensibility = " + this.sensibilityVolume);
                }
            }
        }

        #endregion

        #region Microphone methods
        private void InitializeMicrophone()
        {
            // We already have a microphone, skip out early.
            if (activeMicrophone != null) { return; }

            try
            {
                // Find the first microphone that's ready to rock.
                activeMicrophone = PickFirstConnectedMicrophone();
                if (activeMicrophone != null)
                {
                    // Set the capture buffer size for kow latency.
                    // Microphone will call the game back when it has captured at least that much audio data.
                    activeMicrophone.BufferDuration = TimeSpan.FromMilliseconds(100);
                    // Subscribe to the event that's raised when the capture buffer is filled.
                    activeMicrophone.BufferReady += BufferReady;

                    // We will put the mic samples in this buffer.  We only want to allocate it once.
                    micSamples = new byte[activeMicrophone.GetSampleSizeInBytes(activeMicrophone.BufferDuration)];

                    // This is a circular buffer.  Samples from the mic will be mixed with the oldest sample in this buffer
                    // and written back out to this buffer.  This feedback creates an echo effect.
                    echoBuffer = micSamples;// new byte[activeMicrophone.GetSampleSizeInBytes(TimeSpan.FromSeconds(echoDelay))];

                    // Create a DynamicSoundEffectInstance in the right format to playback the captured audio.
                    //dynamicSound = new DynamicSoundEffectInstance(activeMicrophone.SampleRate, AudioChannels.Mono);
                    //dedectedPitch = micSamples.Max();
                    //dynamicSound.Play()
                }
            }
            catch (NoMicrophoneConnectedException)
            {
                // Uh oh, the microphone was disconnected in the middle of initialization.
                // Let's clean up everything so we can look for another microphone again on the next update.
                activeMicrophone.BufferReady -= BufferReady;
                activeMicrophone = null;
            }
        }

        private void StartMicrophone()
        {
            // Can't start a microphone that doesn't exist.
            if (activeMicrophone == null) { return; }

            try
            {
                if (activeMicrophone.State != MicrophoneState.Started)
                {
                    activeMicrophone.Start();
                }
            }
            catch (NoMicrophoneConnectedException)
            {
                UpdateMicrophoneStatus();
            }
        }

        private void StopMicrophone()
        {
            // Can't stop a microphone that doesn't exist.
            if (activeMicrophone == null) { return; }

            try
            {
                if (activeMicrophone.State != MicrophoneState.Stopped)
                {
                    // Stop the microphone
                    activeMicrophone.Stop();
                    // And clear the echo buffer
                    Array.Clear(echoBuffer, 0, echoBuffer.Length);
                }
            }
            catch (NoMicrophoneConnectedException)
            {
                UpdateMicrophoneStatus();
            }
        }   

        private Microphone PickFirstConnectedMicrophone()
        {
            // Let's pick the default microphone if it's ready.
            if (Microphone.Default != null && Microphone.Default.IsConnected())
            {
                return Microphone.Default;
            }

            // Default microphone seems to be disconnected so look for another microphone that we can use.
            // And if the default was null then the list will be empty and we'll skip the search.
            foreach (Microphone microphone in Microphone.All)
            {
                if (microphone.IsConnected())
                {
                    return microphone;
                }
            }

            // There are no microphones hooked up to the system!
            return null;
        }

        private void UpdateMicrophoneStatus()
        {
            // We don't have any microphones connected to the system.
            if (activeMicrophone == null)
            {
                microphoneStatus = "Waiting for microphone connection...";
            }
            else
            {
                try
                {
                    // Update the status - if the microphone gets disconnected this will throw
                    microphoneStatus = string.Format("{0} is {1}", activeMicrophone.Name, activeMicrophone.State);
                }
                catch (NoMicrophoneConnectedException)
                {
                    // Microphone got disconnected - Let's ask the user to reconnect it.
                    microphoneStatus = string.Format("Please reconnect {0}", activeMicrophone.Name);
                    // Clear the echo buffer
                    Array.Clear(echoBuffer, 0, echoBuffer.Length);
                }
            }
        }

        void BufferReady(object sender, EventArgs e)
        {
            try
            {
                // Copy the captured audio data into the pre-allocated array.
                activeMicrophone.GetData(micSamples, 0, micSamples.Length);
                ProcessSound();
            }
            catch (NoMicrophoneConnectedException)
            {
                // Microphone was disconnected - let the user know.
                UpdateMicrophoneStatus();
            }
        }

        private void ProcessSound()
        {
            for (int index = 0; index < micSamples.Length; index += sizeof(short))
            {
                short micSample = ReadSample(micSamples, index);
                //short echoSample = ReadSample(echoBuffer, echoBufferPosition);

                // Mix the echo back into the buffer
                //short outputSample = (short)((float)micSample);
                WriteSample(echoBuffer, echoBufferPosition, (short)((float)micSample));
                echoBufferPosition += sizeof(short);

                // Play back the encho buffer if it's filled.
                if (echoBufferPosition == echoBuffer.Length)
                {
                    //dynamicSound.SubmitBuffer(echoBuffer, 0, echoBuffer.Length);

                    int sampleCount = echoBuffer.Length / sizeof(short);
                    curDetectedSoundVolume = 0;
                    for (int i = 0; i < echoBuffer.Length; i += sizeof(short))
                    {
                        int sampleIndex = i / sizeof(short);
                        
                        //vertexPosColor[sampleIndex].Position.Y = (GraphicsDevice.Viewport.Height / 2) - );

                        float tmp = (float)ReadSample(echoBuffer, i) ;//( / Int16.MaxValue * (GraphicsDevice.Viewport.Height / 2));
                        curDetectedSoundVolume = Math.Max(curDetectedSoundVolume, tmp);// (dedectedPitch < tmp ? tmp : dedectedPitch);

                    }

                    // Reset the position to the beginning of the buffer.
                    echoBufferPosition = 0;
                }
            }
        }

        /// <summary>
        /// Writes the passed sample value to the buffer,
        /// taking into account the endian-ness of the system.
        /// </summary>
        private void WriteSample(byte[] buffer, int index, short sample)
        {
            // Ensure we're doing aligned writes.
            if (index % sizeof(short) != 0)
            {
                throw new ArgumentException("index");
            }

            if (index >= buffer.Length)
            {
                throw new ArgumentOutOfRangeException("index");
            }
            
            if (bigEndian)
            {
                buffer[index] = (byte)(sample >> 8);
                buffer[index + 1] = (byte)sample;
            }
            else
            {
                buffer[index] = (byte)sample;
                buffer[index + 1] = (byte)(sample >> 8);
            }
        }

        /// <summary>
        /// Returns a sample value from the passed buffer,
        /// taking into account the endian-ness of the system.
        /// </summary>
        private short ReadSample(byte[] buffer, int index)
        {
            
            // Ensure we're doing aligned reads.
            if (index % sizeof(short) != 0)
            {
                throw new ArgumentException("index");
            }

            if (index >= buffer.Length)
            {
                throw new ArgumentOutOfRangeException("index");
            }
            
            short sample = 0;
            if (bigEndian)
            {
                sample = (short)(buffer[index] << 8 | buffer[index + 1] & 0xff);
            }
            else
            {
                sample = (short)(buffer[index] & 0xff | buffer[index + 1] << 8);
            }

            return sample;
        }

        #endregion Micro

        private void initTarget()
        {
            this.posTarget = new Vector2(Window.ClientBounds.Width / 2 - + t2dTarget.Width / 2, 100.0f);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // Unload any non ContentManager content here
        }


        # region Updates

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                this.Exit();

            // Allows the default game to exit on Xbox 360 and Windows
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                this.Exit();

            // draw Background
            switch (gameNow)
            {
                case GAMESTATE.Start_Screen:
                    UpdateBackground(gameTime);
                    break;


                case GAMESTATE.Calibrate:
                case GAMESTATE.Play:
                
                    // Calc background Movment
                    UpdateBackground(gameTime);
                    break;

                default:
                    UpdateBackground(gameTime);
                    break;
            }

            // draw rest
            switch (gameNow)
            {
                case GAMESTATE.Play:

                    UpdateGameScreen(Keyboard.GetState(), gameTime);

                    // Calc ship position
                    UpdateShip(Keyboard.GetState(), gameTime);

                    // Calc Planet Position
                    UpdatePlanets(gameTime);

                    // Calc Enemy Movment
                    UpdateEnemies(gameTime);

                    // Calc Death Enemy
                    UpdateDeathEnemies(gameTime);
                
                    // Calc Shoot Movement
                    UpdateShoots(Mouse.GetState(), wm.WiimoteState, gameTime);


                    // Calc Target position
                    UpdateTarget(Mouse.GetState());

                    _playerScore += (int)GetPlayerElapsedTime(gameTime)/1000;

                    // Doest the player get a new Megabomb 
                    if (_playerScore >= _nextMegaBombBonus*1000)
                    {
                        _nextMegaBombBonus += MegaBombBonusScore;
                        if (_MegaBombsNumber < MaxMegaBombs)
                            _MegaBombsNumber++;
                    }

                    if (GetPlayerElapsedTime(gameTime) >= level * 10000)
                    {
                        level++;
                        if(_isSoundEffectOn)
                            soundLevelup.Play(0.5f, 0.0f, 0.0f);
                    }

                    break;


                case GAMESTATE.Start_Screen:

                    level = 1;
                    UpdateCursor(Mouse.GetState());

                    UpdateButton(Mouse.GetState(), gameTime);

                    UpdateGameScreen(Keyboard.GetState(), gameTime);
                    break;

                case GAMESTATE.Calibrate:
                    UpdateGameScreen(Keyboard.GetState(), gameTime);
                    break;

                case GAMESTATE.Death:
                    UpdateGameScreen(Keyboard.GetState(), gameTime);
                    break;

                case GAMESTATE.Help:
                    UpdateCursor(Mouse.GetState());
                    UpdateButton(Mouse.GetState(), gameTime);
                    UpdateGameScreen(Keyboard.GetState(), gameTime);
                    break;

                default:
                    break;
            }


            switch (gameNow)
            {
                
                case GAMESTATE.Play:
                    InitializeMicrophone();
                    StartMicrophone();

                    break;
                default:
                    StopMicrophone();
                    break;
            }

            // Check and update microphone status.
            UpdateMicrophoneStatus();

            // Update wiimote rumbling state
            if (this.cntWiimoteRumbling-- <= 0)
                this.wm.SetRumble(false);

            base.Update(gameTime);
        }

        private void UpdateGameScreen(KeyboardState keyboardState, GameTime gameTime)
        {
            // Switching between the different game screens    
            switch(gameNow)
            {
                case GAMESTATE.Start_Screen:
                    if (keyboardState.IsKeyDown(Keys.Space))
                    {
                        if (useKinect)
                            gameNow = GAMESTATE.Calibrate;
                        else
                            StartNewGame(gameTime);
                    }
                    break;
                
                case GAMESTATE.Play:
                    if (keyboardState.IsKeyDown(Keys.Escape))
                        gameNow = GAMESTATE.Start_Screen;
                    break;

                case GAMESTATE.Calibrate:
                    if (keyboardState.IsKeyDown(Keys.Escape))
                        gameNow = GAMESTATE.Start_Screen;

                    break;

                case GAMESTATE.Death:
                    if (keyboardState.IsKeyDown(Keys.Escape))
                        gameNow = GAMESTATE.Start_Screen;
                    break;

                case GAMESTATE.Help:
                    if (keyboardState.IsKeyDown(Keys.Escape))
                        gameNow = GAMESTATE.Start_Screen;
                    break;

                default:
                    break;
            }
        }

        // Calc positions of Background img
        private void UpdateBackground(GameTime gameTime)
        {
            if (posBack1.Y > t2dBack1.Height)
            {
                posBack1.Y = posBack2.Y - t2dBack2.Height;
            }

            if (posBack2.Y > t2dBack2.Height)
            {
                posBack2.Y = posBack1.Y - t2dBack1.Height;
            }

            posBack1 += directionBackground * speedBackground * (1 + (level - 1) / 2) * (float)gameTime.ElapsedGameTime.TotalSeconds;
            posBack2 += directionBackground * speedBackground * (1 + (level - 1) / 2) * (float)gameTime.ElapsedGameTime.TotalSeconds;
        }

        // Calc positions of Enemys
        private void UpdateEnemies(GameTime gameTime)
        {

            for (int i = 0; i < posEnemys.Count; i++)
            {
                // Move edemys
                posEnemys[i] += directionEnemy * speedEnemy * (1 + (level - 1) / 2) * (float)gameTime.ElapsedGameTime.TotalSeconds;


                // remove them if neccesery
                if (posEnemys[i].Y > Window.ClientBounds.Height)
                {
                    posEnemys.Remove(posEnemys[i]);
                }
            }

            // Add enemys
            int rand = rndEnemy.Next(100);
            if (rand < chancePerTicForNewEnemy && posEnemys.Count < this.numberOfEnemysMax && posEnemys.Count < level)
            {

                float x = ((float)rndEnemy.NextDouble()) * (this.Window.ClientBounds.Width - t2dEdemy.Width * scallingEnemy);
                float y = -t2dEdemy.Height * scallingEnemy;

                Vector2 posNewEnemy = new Vector2(x, y);

                // Add first eddmy
                if (posEnemys.Count <= 0)
                {
                    //MessageBox(new IntPtr(0), " First in ! ", "whas", 0); ;
                    posEnemys.Add(posNewEnemy);
                }
                else
                {
                    // Controll do not overlap enemys
                    bool add = true;
                    for (int i = 0; i < posEnemys.Count; i++)
                    {
                        if (Utils.CollisionPossible(t2dEdemy, posNewEnemy, scallingEnemy, t2dEdemy, posEnemys[i], scallingEnemy))
                        {
                            add = false;
                            i = posEnemys.Count;
                        }
                    }

                    if (add)
                    {
                        posEnemys.Add(posNewEnemy);
                    }
                }
            }

        }

        // Calc positions of Enemys
        private void UpdatePlanets(GameTime gameTime)
        {

            for (int i = 0; i < posPlanet.Count; i++)
            {
                // Move planet
                posPlanet[i] += directionPlanet * speedPlanet * (1 + (level - 1) / 2) * (float)gameTime.ElapsedGameTime.TotalSeconds;

                // remove them if neccesery
                if (posPlanet[i].Y > Window.ClientBounds.Height)
                {
                    posPlanet.Remove(posPlanet[i]);
                    scallingPlanet.Remove(scallingPlanet[i]);
                }
            }

            // Add planet
            int rand = rndPlanet.Next(100);
            if (rand < chancePerTicForNewPlanet && posPlanet.Count < this.numberOfPlanetMax && posPlanet.Count < level)
            {
                float newScalePlanet = (float)(rndPlanet.NextDouble() * (scallingPlanetMax - scallingPlanetMin) + scallingPlanetMin);

                float x = ((float)rndPlanet.NextDouble()) * (this.Window.ClientBounds.Width - t2dPlanet.Width * newScalePlanet);
                float y = -t2dPlanet.Height * newScalePlanet;

                Vector2 posNewPlanet = new Vector2(x, y);

                // Add first eddmy
                if (posPlanet.Count <= 0)
                {
                    //MessageBox(new IntPtr(0), " First in ! ", "whas", 0); ;
                    posPlanet.Add(posNewPlanet);
                    scallingPlanet.Add(newScalePlanet);
                }
                else
                {
                    // Controll do not overlap enemys
                    bool add = true;
                    for (int i = 0; i < posPlanet.Count; i++)
                    {
                        if (Utils.CollisionPossible(t2dPlanet, posNewPlanet, newScalePlanet, t2dPlanet, posPlanet[i], scallingPlanet[i]))
                        {
                            add = false;
                            i = posPlanet.Count;
                        }
                    }

                    if (add)
                    {
                        posPlanet.Add(posNewPlanet);
                        scallingPlanet.Add(newScalePlanet);
                    }
                }
            }

        }

        // Calc position of DeathEnemys
        private void UpdateDeathEnemies(GameTime gameTime)
        {
            for (int i = 0; i < posDeathEnemys.Count; i++)
            {
                if (remainingTimeDeathEnemys[i]-- < 0)
                {
                    posDeathEnemys.Remove(posDeathEnemys[i]);
                    remainingTimeDeathEnemys.Remove(remainingTimeDeathEnemys[i]);
                }
            }
        }

        // Calc position of Ship 
        private void UpdateShip(KeyboardState aCurrentKeyboardState, GameTime gameTime)
        {
            if (aCurrentKeyboardState.IsKeyDown(Keys.Right) || aCurrentKeyboardState.IsKeyDown(Keys.D))
            {
                if ((posShip.X + aMoveDist) < (this.Window.ClientBounds.Width - (t2dShip.Width * ScallingShip)))
                    posShip.X += aMoveDist;
            }

            if (aCurrentKeyboardState.IsKeyDown(Keys.Left) || aCurrentKeyboardState.IsKeyDown(Keys.A))
            {
                if ((posShip.X - aMoveDist) > 0)
                    posShip.X -= aMoveDist;
            }

            if (_isPlayerImmune)
            {
                imunPassedTime += gameTime.ElapsedGameTime.Milliseconds;

                if (imunPassedTime >= imunMaxTime)
                {
                    _isPlayerImmune = false;
                    imunPassedTime = 0;
                }
            }
            else
            {
                mtrShip = Utils.CreateTranslationMatrix(Vector2.Zero, posShip, 0, ScallingShip);

                // Control if collision with enemy
                for (int i = 0; i < posEnemys.Count && gameNow == GAMESTATE.Play && !_isPlayerImmune; i++)
                {
                    if (Utils.CollisionPossible(t2dShip, posShip, ScallingShip, t2dEdemy, posEnemys[i], scallingEnemy))
                    {

                        mtrEnemy = Utils.CreateTranslationMatrix(Vector2.Zero, posEnemys[i], 0, scallingEnemy);

                        if (Utils.ObjectCollision(textureDataShip, mtrShip, textureDataEnemy, mtrEnemy))
                        {
                            //MessageBox(new IntPtr(0), " AUTSCH  !! ", "whas", 0);
                            shipHealth -= 10;
                            _isPlayerImmune = true;
                            shipRecoveryPassedTime = 0;

                            // activate wiimote rumbling
                            this.cntWiimoteRumbling = this.wiimoteRumblingTime;
                            wm.SetRumble(true);
                        }
                    }
                }

                // Control if collision with Planet
                for (int i = 0; i < posPlanet.Count && gameNow == GAMESTATE.Play && !_isPlayerImmune; i++)
                {
                    if (Utils.CollisionPossible(t2dShip, posShip, ScallingShip, t2dPlanet, posPlanet[i], scallingPlanet[i]))
                    {

                        mtrPlanet = Utils.CreateTranslationMatrix(Vector2.Zero, posPlanet[i], 0, scallingPlanet[i]);

                        if (Utils.ObjectCollision(textureDataShip, mtrShip, textureDataPlanet, mtrPlanet))
                        {
                            //MessageBox(new IntPtr(0), " AUTSCH  !! ", "whas", 0);
                            shipHealth -= 15;
                            _isPlayerImmune = true;
                            shipRecoveryPassedTime = 0;

                            // activate wiimote rumbling
                            this.cntWiimoteRumbling = this.wiimoteRumblingTime;
                            wm.SetRumble(true);
                        }
                    }
                }

                // controll if death
                if (shipHealth <= 0)
                {
                    gameNow = GAMESTATE.Death;
                    shipHealth = 0;
                }

                // Recovery health
                if (!_isPlayerImmune && shipHealth < maxShipHealth)
                {
                    shipRecoveryPassedTime += gameTime.ElapsedGameTime.Milliseconds;

                    if (shipRecoveryPassedTime >= shipRecovery)
                    {
                        shipHealth++;
                        shipRecoveryPassedTime -= shipRecovery;
                    }
                }
            }
        }

        // Update shoots
        private void UpdateShoots(MouseState aCurrentMouseState, WiimoteState aCurrentWiimoteState, GameTime gameTime)
        {
            // update position of shoot(s) currently in progress
            for (int i = 0; i < posShoot.Count; i++)
            {
                // move the shoot
                posShoot[i] += directionShoot[i] * speedShoot * (float)gameTime.ElapsedGameTime.TotalSeconds;

                // remove the shoot if it reach the top of the screen
                if (posShoot[i].Y <= 0)
                {
                    posShoot.Remove(posShoot[i]);
                    directionShoot.Remove(directionShoot[i]);
                    continue;
                }

                // Controls collision
                mtrShoot = Utils.CreateTranslationMatrix(Vector2.Zero, posShoot[i], (float)Math.Tan(directionShoot[i].Y/directionShoot[i].X), ScallingShip);
                bool hasCollisionOccured = false;

                // Controll if collsion with enemy
                for (int u = 0; u < posEnemys.Count; u++)
                {
                    if (Utils.CollisionPossible(t2dShoot, posShoot[i], scallingShoot, t2dEdemy, posEnemys[u], scallingEnemy))
                    {

                        mtrEnemy = Utils.CreateTranslationMatrix(Vector2.Zero, posEnemys[u], 0, scallingEnemy);

                        if (Utils.ObjectCollision(textureDataShoot, mtrShoot, textureDataEnemy, mtrEnemy))
                        {
                            //Update ship health or score
                            if(shipHealth < maxShipHealth) shipHealth += 1;
                            else _playerScore += HitEnemyScore;
                            
                            
                            if(_isSoundEffectOn)
                                soundExplosion.Play(0.1f, 0.0f, 0.0f);
                            
                            // display death enemy
                            posDeathEnemys.Add(posEnemys[u]);
                            remainingTimeDeathEnemys.Add(durationDeathEnemy);

                            // remove enemy
                            posEnemys.Remove(posEnemys[u]);
                            posShoot.Remove(posShoot[i]);
                            directionShoot.Remove(directionShoot[i]);

                            hasCollisionOccured = true;
                            break;
                        }
                    }
                }

                if (!hasCollisionOccured)
                {
                    // Controll if collsion with Planet
                    for (int u = 0; u < posPlanet.Count; u++)
                    {
                        if (Utils.CollisionPossible(t2dShoot, posShoot[i], scallingShoot, t2dPlanet, posPlanet[u], scallingPlanet[u]))
                        {

                            mtrPlanet = Utils.CreateTranslationMatrix(Vector2.Zero, posPlanet[u], 0, scallingPlanet[u]);

                            if (Utils.ObjectCollision(textureDataShoot, mtrShoot, textureDataPlanet, mtrPlanet))
                            {
                                //MessageBox(new IntPtr(0), " AUTSCH  !! ", "whas", 0);
                                posShoot.Remove(posShoot[i]);
                                directionShoot.Remove(directionShoot[i]);
                                break;
                            }
                        }
                    }
                }
            }

            // ------- Add shoot -------
            previousMouseState = currentMouseState;
            currentMouseState = aCurrentMouseState;

            previousWiimoteState = currentWiimoteState;
            currentWiimoteState = aCurrentWiimoteState.ButtonState.B;

            wasSoundShooting = shouldSoundShooting;
            shouldSoundShooting = (curDetectedSoundVolume - oldDetectedSoundVolume) >= sensibilityVolume;
            oldDetectedSoundVolume = curDetectedSoundVolume;

            if (shouldSoundShooting && !wasSoundShooting)
            {
                // Destroy everything
                UpdateMegaBombEffect();
            }

            if ((currentMouseState.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed && previousMouseState.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Released)
                || (currentWiimoteState && !previousWiimoteState) )
            {
                // Play a sound
                if(_isSoundEffectOn)
                    soundBlast.Play(0.30f, 0.0f, 0.0f);
                
                // Create and place the new shoot
                float x = ((float)posShip.X + (t2dShip.Width*ScallingShip/4)-8);
                float y = ((float)posShip.Y);

                // Compute direction 
                float xDir = posTarget.X - x;
                float yDir = posTarget.Y - y;

                Vector2 posNewShoot = new Vector2(x, y);
                Vector2 directionNewShoot = new Vector2(xDir, yDir);

                
                // Controll do not overlap shoots
                bool add = true;
                for (int i = 0; i < posShoot.Count; i++)
                {
                    if (Utils.CollisionPossible(t2dShoot, posNewShoot, scallingShoot, t2dShoot, posShoot[i], scallingShoot))
                    {
                        add = false;
                        i = posShoot.Count;
                    }
                }

                if (add)
                {
                    posShoot.Add(posNewShoot);
                    directionShoot.Add(directionNewShoot);
                    posNewShoot.X += (t2dShip.Width * ScallingShip / 2);
                    posShoot.Add(posNewShoot);
                    directionShoot.Add(directionNewShoot);
                }
            }
        }

        // The mega bomb destroys a lot of stuff
        private void UpdateMegaBombEffect()
        {
            if (_MegaBombsNumber > 0)
            {
                int enemies = posEnemys.Count;
                List<int> enemiesToRemove = new List<int>();
                for (int u = 0; u < enemies; u++)
                {
                    if (_isSoundEffectOn)
                        soundExplosion.Play(0.1f, 0.0f, 0.0f);

                    // display death enemy
                    posDeathEnemys.Add(posEnemys[u]);
                    remainingTimeDeathEnemys.Add(durationDeathEnemy);

                    // Mark to remove
                    enemiesToRemove.Add(u);
                    _playerScore += HitEnemyScore;
                }

                foreach (int enemyIndex in enemiesToRemove)
                    // remove enemy
                    posEnemys.Remove(posEnemys[0]);

                _MegaBombsNumber--;
            }
        }

        // Move the target
        private void UpdateTarget(MouseState aCurrentMouseState)
        {
            /*
            if (aCurrentMouseState.X > 0 && aCurrentMouseState.X < Window.ClientBounds.Width)
            {
                posTarget = new Vector2(aCurrentMouseState.X, 100.0f);
            }*/

            // Détection de l'accélération gauche - droite de la wiimote pour le viseur
            /*if (wm.WiimoteState.AccelState.Values.X > 0.3)
            {
                if(this.posTarget.X < Window.ClientBounds.Width - this.t2dTarget.Width) this.posTarget.X += 15;
            }
            else if (wm.WiimoteState.AccelState.Values.X < -0.3)
            {
                if(this.posTarget.X > 0) posTarget.X -= 15;
            }*/
            float xPos = 0.0f;
            float yPos = 0.0f;
            int nbDetected = 0;
            for (int i=0; i < 1; i++)
            {
                IRSensor ir = wm.WiimoteState.IRState.IRSensors[i];
                if (ir.Found)
                {
                    xPos += ir.Position.X;
                    yPos += ir.Position.Y;
                    nbDetected++;
                }
            }
            if (nbDetected > 0)
            {
                

                xPos = xPos / nbDetected;
                yPos = yPos / nbDetected;
                xPos = this.targetZoneWidth - xPos * targetZoneWidth;
                yPos = yPos * targetZoneHeight;

                posTarget = new Vector2(xPos, yPos);
            }
            
        }

        private void UpdateCursor(MouseState aCurrentMouseState)
        {
            posCursor.X = aCurrentMouseState.X;
            posCursor.Y = aCurrentMouseState.Y;
        }

        private void UpdateButton(MouseState aCurrentMouseState, GameTime gameTime)
        {
            // Check if the mouse is on the Play button
            if (gameNow == GAMESTATE.Start_Screen)
            {
                if (Utils.MousInRectangle(aCurrentMouseState,
                                          new Rectangle((int) posPlayText.X, (int) posPlayText.Y, t2dPlayText.Width,
                                                        t2dPlayText.Height)))
                {
                    isMouseOverPlayButton = true;

                    if (aCurrentMouseState.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                    {
                        // The player has clicked on the start button. If a kinect was dected, the game switch onto the calibrate screen
                        if (useKinect)
                        {
                            // The timeout for calibration starts
                            calibrationStart = DateTime.Now;
                            gameNow = GAMESTATE.Calibrate;
                        }
                        else
                            StartNewGame(gameTime);
                    }
                }
                else
                {
                    isMouseOverPlayButton = false;
                }

                // Check if the mouse is on the Help button

                if (Utils.MousInRectangle(aCurrentMouseState,
                                          new Rectangle((int) posHelpText.X, (int) posHelpText.Y, t2dHelpText.Width,
                                                        t2dHelpText.Height)))
                {
                    isMouseOverHelpButton = true;

                    if (aCurrentMouseState.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                    {
                        // Launch Help Screen;
                        gameNow = GAMESTATE.Help;
                    }
                }
                else
                {
                    isMouseOverHelpButton = false;
                }

                // Check if the mouse is on the Quit button

                if (Utils.MousInRectangle(aCurrentMouseState,
                                          new Rectangle((int) posQuitText.X, (int) posQuitText.Y, t2dQuitText.Width,
                                                        t2dQuitText.Height)))
                {
                    isMouseOverQuitButton = true;

                    if (aCurrentMouseState.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                    {
                        // Exit the game
                        Exit();
                    }
                }
                else
                {
                    isMouseOverQuitButton = false;
                }
            }
            // Check if the mouse is on the Back button
            if (gameNow == GAMESTATE.Help)
            {
                if (Utils.MousInRectangle(aCurrentMouseState,
                                          new Rectangle((int) posBackText.X, (int) posBackText.Y, t2dBackText.Width,
                                                        t2dBackText.Height)))
                {
                    isMouseOverBackButton = true;

                    if (aCurrentMouseState.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                    {
                        gameNow = GAMESTATE.Start_Screen;
                    }
                }
                else
                {
                    isMouseOverBackButton = false;
                }
            }
        }

        #endregion

        #region Draws

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // Draw
            mBatch.Begin();

            // Background 
            DrawBackground(gameTime);

            switch (gameNow)
            {
                case GAMESTATE.Start_Screen:

                    // Draw the start screen title and buttons
                    mBatch.Draw(t2dGameTitle, posGameTitle, new Rectangle(0, 0, t2dGameTitle.Width, t2dGameTitle.Height),
                                new Color(255, 255, 255, 255), 0.0f, Vector2.Zero, 1, SpriteEffects.None, 0);

                    posPlayText = new Vector2(Window.ClientBounds.Width/2 - t2dPlayText.Width/2,
                                              posGameTitle.Y + t2dGameTitle.Height + 50);

                    posHelpText = new Vector2(Window.ClientBounds.Width / 2 - t2dHelpText.Width / 2,
                                             posPlayText.Y + t2dPlayText.Height + 50);

                    posQuitText = new Vector2(Window.ClientBounds.Width / 2 - t2dQuitText.Width / 2,
                                             posHelpText.Y + t2dHelpText.Height + 50);
                    
                    if (!isMouseOverPlayButton)
                        {
                            mBatch.Draw(t2dPlayText, posPlayText,
                                        new Rectangle(0, 0, t2dPlayText.Width, t2dPlayText.Height),
                                        new Color(255, 255, 255, 255), 0.0f, Vector2.Zero, 1, SpriteEffects.None, 0);
                        }
                    else
                        {
                            mBatch.Draw(t2dPlayTextRed, posPlayText,
                                        new Rectangle(0, 0, t2dPlayText.Width, t2dPlayText.Height),
                                        new Color(255, 255, 255, 255), 0.0f, Vector2.Zero, 1, SpriteEffects.None, 0);

                        }

                    if (!isMouseOverHelpButton)
                    {
                        mBatch.Draw(t2dHelpText, posHelpText,
                                    new Rectangle(0, 0, t2dHelpText.Width, t2dHelpText.Height),
                                    new Color(255, 255, 255, 255), 0.0f, Vector2.Zero, 1, SpriteEffects.None, 0);
                    }
                    else
                    {
                        mBatch.Draw(t2dHelpTextRed, posHelpText,
                                   new Rectangle(0, 0, t2dHelpText.Width, t2dHelpText.Height),
                                   new Color(255, 255, 255, 255), 0.0f, Vector2.Zero, 1, SpriteEffects.None, 0);

                    }

                    if (!isMouseOverQuitButton)
                    {
                        mBatch.Draw(t2dQuitText, posQuitText,
                                    new Rectangle(0, 0, t2dQuitText.Width, t2dQuitText.Height),
                                    new Color(255, 255, 255, 255), 0.0f, Vector2.Zero, 1, SpriteEffects.None, 0);
                    }
                    else
                    {
                        mBatch.Draw(t2dQuitTextRed, posQuitText,
                                    new Rectangle(0, 0, t2dQuitText.Width, t2dQuitText.Height),
                                    new Color(255, 255, 255, 255), 0.0f, Vector2.Zero, 1, SpriteEffects.None, 0);
                    }

                    //this.IsMouseVisible = true;
                    DrawCursor();

                    break;

                case GAMESTATE.Death :

                    String death = "Game Over";
                    String points = " Your Score: " + Utils.GetScoreSeconds(_playerScore);
                    Vector2 deathSize = titleFont.MeasureString(death);
                    Vector2 pointsSize = gameFont.MeasureString(points);

                    mBatch.DrawString(titleFont, death, new Vector2(this.Window.ClientBounds.Width / 2, this.Window.ClientBounds.Height / 2), Color.Red, 0, new Vector2(deathSize.X / 2, deathSize.Y / 2), 1.0f, SpriteEffects.None, 0);
                    mBatch.DrawString(this.gameFont, points, new Vector2(this.Window.ClientBounds.Width / 2, this.Window.ClientBounds.Height / 2 + deathSize.Y), Color.Red, 0, new Vector2(pointsSize.X / 2, pointsSize.Y / 2), 1.0f, SpriteEffects.None, 0);

                    goto case GAMESTATE.Play;

                case GAMESTATE.Play :
                    
                    /* DEBUG
                    mBatch.DrawString(this.gameFont, "Enemyis: " + posEnemys.Count, new Vector2(10, 10), Color.Beige);
                    mBatch.DrawString(this.gameFont, "First in: " + firstInCounter, new Vector2(10, 26), Color.Beige);
                    mBatch.DrawString(this.gameFont, "Second passed: " + gameTime.TotalGameTime.TotalSeconds, new Vector2(10, 80), Color.Beige);
                    */

                    this.IsMouseVisible = false;

                    // Planets
                    DrawPlanets(gameTime);

                    // Enemys
                    DrawEnemy(gameTime);

                    // Death enemy
                    DrawDeathEnemy(gameTime);

                    // Shoot
                    DrawShoot(gameTime);

                    // Target
                    DrawTarget();

                    // Draw Bombs
                    DrawMegaBombs();

                    // Ship
                    mBatch.Draw(t2dShip, posShip, new Rectangle(0, 0, t2dShip.Width, t2dShip.Height),
                        new Color(255, 255, 255, (_isPlayerImmune ? 0 : 255)), 0.0f, Vector2.Zero, ScallingShip, SpriteEffects.None, 0);
                
                    // print Score
                    String zeros = "Score : 000000";
                    mBatch.DrawString(gameFont, "Score : " + Utils.GetScoreSeconds(_playerScore), new Vector2(Window.ClientBounds.Width - gameFont.MeasureString(zeros).Length() - 20, 10), _mainColor);
                    mBatch.DrawString(gameFont, "Level : " + level, new Vector2(10, 10), _mainColor);

                    DrawHealthBar();
                    break;

                case GAMESTATE.Help:

                    mBatch.Draw(t2dHelpPicture, new Vector2(0,0),
                                    new Rectangle(0, 0, t2dHelpPicture.Width, t2dHelpPicture.Height),
                                    new Color(255, 255, 255, 255), 0.0f, Vector2.Zero, 1, SpriteEffects.None, 0);
                    
                    DrawCursor();

                    posBackText = new Vector2(Window.ClientBounds.Width / 2 - t2dPlayText.Width / 2,
                                              Window.ClientBounds.Height * 2 / 3 + 100);

                    if (!isMouseOverBackButton)
                    {
                        mBatch.Draw(t2dBackText, posBackText,
                                    new Rectangle(0, 0, t2dBackText.Width, t2dBackText.Height),
                                    new Color(255, 255, 255, 255), 0.0f, Vector2.Zero, 1, SpriteEffects.None, 0);
                    }
                    else
                    {
                        mBatch.Draw(t2dBackTextRed, posBackText,
                                    new Rectangle(0, 0, t2dBackText.Width, t2dBackText.Height),
                                    new Color(255, 255, 255, 255), 0.0f, Vector2.Zero, 1, SpriteEffects.None, 0);

                    }
                    break;

                case GAMESTATE.Calibrate:
                    DrawCalibrationScreen(gameTime);
                    break;
            }

            /* debug */
            /*
            mBatch.DrawString(this.gameFont, " Delta : " + sensibilityVolume, new Vector2(40, 80), Color.Beige);
            mBatch.DrawString(this.gameFont, " Pitch : " + curDetectedSoundVolume, new Vector2(40, 120), Color.Beige);
            mBatch.DrawString(this.gameFont, " Level : " + level, new Vector2(40, 160), Color.Beige);
            */
            
            mBatch.End();

            base.Draw(gameTime);
        }

        private void DrawEnemy(GameTime gameTime)
        {
            posEnemys.ForEach(delegate(Vector2 position)
            {
                mBatch.Draw(t2dEdemy, position, new Rectangle(0, 0, t2dEdemy.Width, t2dEdemy.Height),
                Color.White, 0.0f, Vector2.Zero, scallingEnemy, SpriteEffects.None, 0);
            });
        }

        private void DrawDeathEnemy(GameTime gameTime)
        {
            for(int i=0; i<posDeathEnemys.Count; i++)
            {
                mBatch.Draw(t2dDeathEnemy, posDeathEnemys[i], new Rectangle(0, 0, t2dDeathEnemy.Width, t2dDeathEnemy.Height),
                Color.White, 0.0f, Vector2.Zero, scallingDeathEnemy, SpriteEffects.None, 0);
            }
        }

        private void DrawPlanets(GameTime gameTime)
        {
            for (int i = 0; i < posPlanet.Count; i++)
            {
                mBatch.Draw(t2dPlanet, posPlanet[i], new Rectangle(0, 0, t2dPlanet.Width, t2dPlanet.Height),
                Color.White, 0.0f, Vector2.Zero, scallingPlanet[i], SpriteEffects.None, 0);
            }
        }

        private void DrawShoot(GameTime gameTime)
        {
            for (int i = 0; i < posShoot.Count; i++)
            {
                mBatch.Draw(t2dShoot, posShoot[i], new Rectangle(0, 0, t2dShoot.Width, t2dShoot.Height), 
                Color.White, (float)Math.Tan(directionShoot[i].X / -(directionShoot[i].Y)), Vector2.Zero, scallingShoot, SpriteEffects.None, 0);

            }
        }

        private void DrawTarget()
        {
            mBatch.Draw(t2dTarget, posTarget, new Rectangle(0, 0, t2dTarget.Width, t2dTarget.Height),
            Color.White, 0.0f, Vector2.Zero, scallingTarget, SpriteEffects.None, 0);
        }

        private void DrawCursor()
        {
            mBatch.Draw(t2dCursor, posCursor, Color.White);
        }

        private void DrawBackground(GameTime gameTime)
        {
            mBatch.Draw(t2dBack1, posBack1, new Rectangle(0, 0, t2dBack1.Width, t2dBack1.Height),
                Color.White, 0.0f, Vector2.Zero, scallingBack, SpriteEffects.None, 0);

            mBatch.Draw(t2dBack1, posBack2, new Rectangle(0, 0, t2dBack1.Width, t2dBack1.Height),
                Color.White, 0.0f, Vector2.Zero, scallingBack, SpriteEffects.None, 0);
        }

        private void DrawHealthBar()
        {

            //Draw the box around the health bar
            mBatch.Draw(t2dHealthBar, new Rectangle(this.Window.ClientBounds.Width / 2 - t2dHealthBar.Width / 2,
                  30, t2dHealthBar.Width, 44), new Rectangle(0, 0, t2dHealthBar.Width, 44), Color.Red);
            
            //Draw the health for the health bar
            mBatch.Draw(t2dHealthBar, new Rectangle(this.Window.ClientBounds.Width / 2 - t2dHealthBar.Width / 2, 30, (int)(t2dHealthBar.Width * ((double)shipHealth / 100)), 44),
                new Rectangle(0, 45, t2dHealthBar.Width, 44), (_isPlayerImmune ? Color.Red : _mainColor));
            
        }

        private void DrawMegaBombs()
        {

            float height = Window.ClientBounds.Height - t2dMegabomb.Height * scallingMegabomb - 40 - t2dShip.Height * ScallingShip;
            
            for (int i = 0; i < _MegaBombsNumber; i++)
            {
                Vector2 posMegabomb = new Vector2(20, height);
                mBatch.Draw(t2dMegabomb, posMegabomb, new Rectangle(0, 0, t2dMegabomb.Width, t2dMegabomb.Height),
                            new Color(255, 255, 255, 255), 0.0f, Vector2.Zero, scallingMegabomb, SpriteEffects.None, 0);

                height -= (t2dMegabomb.Height * scallingMegabomb + 10);
            }
                
        }

        // Draw the kinect psi pose to help the player 
        private void DrawCalibrationScreen(GameTime gameTime)
        {
            if (isKinectCalibrated)
            {
                // If the player is detected, the picture is green and after a short delay the game starts
                TimeSpan timeElapsedSinceSucess = DateTime.Now.Subtract(calibrationSuccess);
                int timeLeftInSeconds = CalibrationSucessTimeout - (int)timeElapsedSinceSucess.TotalSeconds;
                if (timeLeftInSeconds >= 0)
                {
                    // Message sucessful calibration
                    mBatch.Draw(kinectPsiPoseGreen2D,
                                kinectPsiPoseVector,
                                new Rectangle(0, 0, kinectPsiPose2D.Width, kinectPsiPose2D.Height),
                                new Color(255, 255, 255, 255),
                                0.0f,
                                Vector2.Zero,
                                1,
                                SpriteEffects.None,
                                0);
                    Text calibrationText = new Text("Kinect successfuly calibrated. The game will start in "
                                                    + timeLeftInSeconds.ToString() + " seconds");
                    mBatch.DrawString(helpFont,
                                      calibrationText.toString(),
                                      new Vector2(Window.ClientBounds.Width/2, Window.ClientBounds.Height*3/4),
                                      Color.LightGreen,
                                      0,
                                      calibrationText.GetMiddleOrigine(helpFont),
                                      1.0f,
                                      SpriteEffects.None,
                                      0);

                }
                else
                {
                    // Game starts
                    StartNewGame(gameTime);
                }

            }
            else
            {
                // Kinect has not detected yet a player. 
                TimeSpan timeElapsedDuringCalibration = DateTime.Now.Subtract(calibrationStart);
                if (timeElapsedDuringCalibration.TotalSeconds >= CalibrationTimeoutSeconds)
                {
                    // The kinect has failed to detect a player, the game starts
                    int timeLeftInSeconds = CalibrationSucessTimeout + CalibrationTimeoutSeconds -
                                            (int) timeElapsedDuringCalibration.TotalSeconds;
                    if(timeLeftInSeconds >= 0)
                    {
                        mBatch.Draw(kinectPsiPoseRed2D,
                                kinectPsiPoseVector,
                                new Rectangle(0, 0, kinectPsiPose2D.Width, kinectPsiPose2D.Height),
                                new Color(255, 255, 255, 255),
                                0.0f,
                                Vector2.Zero,
                                1,
                                SpriteEffects.None,
                                0);

                        Text calibrationText =
                            new Text("Kinect calibration failed, the game will start in " + timeLeftInSeconds.ToString() + " seconds");
                        mBatch.DrawString(helpFont,
                                          calibrationText.toString(),
                                          new Vector2(this.Window.ClientBounds.Width / 2, this.Window.ClientBounds.Height * 3 / 4),
                                          Color.Red,
                                          0,
                                          calibrationText.GetMiddleOrigine(helpFont),
                                          1.0f,
                                          SpriteEffects.None,
                                          0);
                    }
                    else
                    {
                        // Game starts without kinect
                        StartNewGame(gameTime);
                    }
                }
                else
                {
                    // There still time to detect the user before the timeout
                    mBatch.Draw(kinectPsiPose2D,
                                kinectPsiPoseVector,
                                new Rectangle(0, 0, kinectPsiPose2D.Width, kinectPsiPose2D.Height),
                                new Color(255, 255, 255, 255),
                                0.0f,
                                Vector2.Zero,
                                1,
                                SpriteEffects.None,
                                0);

                    Text calibrationText =
                        new Text("Please place your hands like the picture above until it becomes green");
                    mBatch.DrawString(helpFont,
                                      calibrationText.toString(),
                                      new Vector2(this.Window.ClientBounds.Width/2, this.Window.ClientBounds.Height*3/4),
                                      Color.LightSteelBlue,
                                      0,
                                      calibrationText.GetMiddleOrigine(helpFont),
                                      1.0f,
                                      SpriteEffects.None,
                                      0);
                    }
                }
            }

        #endregion

        // Mise à jour de la position du joueur
        void KinectSkeletonUserUpdated(object sender, NuiUserEventArgs e)
        {
            int userNumber = 1;
            // Si cette méthode est appelée, c'est qu'un utilisateur a été détecté.
            if(!isKinectCalibrated)
            {
                isKinectCalibrated = true;
                calibrationSuccess = DateTime.Now;
            }
            if(gameNow == GAMESTATE.Play)
            {   
                // The ship don't move if the game is not started
                foreach (var user in e.Users)
                {
                    // Il ne faut prendre en compte que le premier utilisateur. Puisque e.Users n'a pas de compte, il ne se passe rien si d'autres joueurs sont trouvés.
                    if(userNumber == 1)
                    {
                        // Détermination du lieu où doit se trouver le personnage sur le jeu
                        float userPositionX =  (user.Torso.X * kinectPixel);
                        if (userPositionX < 0)
                            userPositionX = 0;
                        if(userPositionX > (ScreenWidth- (t2dShip.Width * ScallingShip)))
                            userPositionX = (ScreenWidth- (t2dShip.Width * ScallingShip));
                        posShip.X = userPositionX;
                    
                  }
                    userNumber++;
                }
            }
        }

        private void StartNewGame(GameTime gameTime)
        {
            _MegaBombsNumber = MaxMegaBombs;
            _playerScore = 0;
            level = 1;            
            shipHealth = 100;
            _playerGameTime = new TimeSpan(gameTime.TotalGameTime.Days,
                                            gameTime.TotalGameTime.Hours,
                                            gameTime.TotalGameTime.Minutes,
                                            gameTime.TotalGameTime.Seconds,
                                            gameTime.TotalGameTime.Milliseconds
                                            );
            gameNow = GAMESTATE.Play;
        }

        // Return the total played time by the current player
        private double GetPlayerElapsedTime(GameTime gameTime)
        {
            return (gameTime.TotalGameTime.TotalMilliseconds - _playerGameTime.TotalMilliseconds);
        }

    }

    public class Utils
    {

        // Methode qui controlle si il y a collision du rectangle qui les entoures
        public static bool CollisionPossible(Texture2D img1, Vector2 pos1, float scale1, Texture2D img2, Vector2 pos2, float scale2)
        {
            Rectangle rec1 = new Rectangle((int)pos1.X, (int)pos1.Y, (int)(img1.Width * scale1), (int)(img1.Height * scale1));
            Rectangle rec2 = new Rectangle((int)pos2.X, (int)pos2.Y, (int)(img2.Width * scale2), (int)(img2.Height * scale2));

            return rec1.Intersects(rec2);
        }

        public static bool MousInRectangle(MouseState m, Rectangle r)
        {
            return r.Contains(new Microsoft.Xna.Framework.Point(m.X, m.Y));
        }

        // get Vector2 with position of opposit corner
        public static Vector2 GetOpositCorner(Texture2D img, Vector2 corner, float scale)
        {
            Vector2 res = new Vector2();

            res.X = corner.X + img.Width * scale;
            res.Y = corner.Y + img.Height * scale;

            return res;
        }


        public static Color[,] TextureTo2DArray(Texture2D Texture)
        {
            Color[] TextureColor1D = new Color[Texture.Width * Texture.Height];  //Create Space in Memory for Texture
            Texture.GetData(TextureColor1D);                                     //Use XNA Built-In GetData Method   
            Color[,] TextureColor2D = new Color[Texture.Width, Texture.Height]; //1D has a '*'  - 2D has a ','      
            for (int x = 0; x < Texture.Width; x++)                              //Outer loop is width               
                for (int y = 0; y < Texture.Height; y++)                         //Inner loop is height              
                    TextureColor2D[x, y] = TextureColor1D[x + y * Texture.Width];  //Perform the conversion            
            return TextureColor2D;                                               //Done Cooking - Ready to eat       
        }

        //Create the Translation Matrix for each sprite rendered on the screen:

        public static Matrix CreateTranslationMatrix(Vector2 origin, Vector2 pos, float rotation, float scale)
        {
            Matrix mt =                 
                Matrix.CreateTranslation(origin.X, origin.Y, 0) *        //1. Create Origin Matrix    
                Matrix.CreateRotationZ(rotation) *                             //2. Create Rotation Matrix  
                Matrix.CreateScale(scale) *                                //3. Create Scaling Matrix   
                Matrix.CreateTranslation(pos.X, pos.Y, 0);     //4. Create Position Matrix  

            return mt;
        }

        //Check to See if two image objects are overlapping

        public static bool ObjectCollision(Color[,] PixelsOfObject1, Matrix MatrixOfObject1,
                              Color[,] PixelsOfObject2, Matrix MatrixOfObject2)
        {
            const int WidthDimension = 0;  //Width Dimension Index    
            const int HeightDimension = 1;  //Height Dimension Index   

            //Create a link between both objects
            Matrix MapObject1ToObject2 = MatrixOfObject1 * Matrix.Invert(MatrixOfObject2);

            //Get Array Width and Height Size
            int WidthOfObject1 = PixelsOfObject1.GetLength(WidthDimension);
            int HeightOfObject1 = PixelsOfObject1.GetLength(HeightDimension);
            int WidthOfObject2 = PixelsOfObject2.GetLength(WidthDimension);
            int HeightOfObject2 = PixelsOfObject2.GetLength(HeightDimension);

            //Declare Loop Variables
            int Object1HorizontalPosition;
            int Object1VerticalPosition;
            int Object2HorizontalPosition;
            int Object2VerticalPosition;

            //Loop through Horizontal Pixels of Object 1
            for (Object1HorizontalPosition = 0; Object1HorizontalPosition < WidthOfObject1; Object1HorizontalPosition++)
            {

                //Loop through Vertical Pixels of Object 1
                for (Object1VerticalPosition = 0; Object1VerticalPosition < HeightOfObject1; Object1VerticalPosition++)
                {

                    //We need Object1 Position in Vector format for the Vector2.transform method
                    Vector2 object1Pixel = new Vector2(Object1HorizontalPosition, Object1VerticalPosition);

                    //Create Single Point Pixel containing Object2 characteristics at screen position under analysis
                    Vector2 object2Pixel = Vector2.Transform(object1Pixel, MapObject1ToObject2);

                    //Extract X&Y coordinate information from the Pixel we just created
                    Object2HorizontalPosition = (int)object2Pixel.X;
                    Object2VerticalPosition = (int)object2Pixel.Y;

                    //Test to see if created pixel is within bounds on horizontal axis
                    if (Object2HorizontalPosition >= 0 && Object2HorizontalPosition < WidthOfObject2)
                    {

                        //Test to see if created pixel is within bounds on vertical axis
                        if (Object2VerticalPosition >= 0 && Object2VerticalPosition < HeightOfObject2)
                        {

                            //Test to see if Object1 pixel under analysis is visible or transparent (Alpha Component)
                            if (PixelsOfObject1[Object1HorizontalPosition, Object1VerticalPosition].A > 0)
                            {

                                //Test to see if Object2 pixel under analysis is visible or transparent 
                                if (PixelsOfObject2[Object2HorizontalPosition, Object2VerticalPosition].A > 0)
                                {

                                    //All criterion have been met → Pixel Overlap → Collision 
                                    return true;
                                }
                            }
                        }
                    }
                }
            }
            return false;
        }

        public static String GetScoreSeconds(int scoreMiliSeconds)
        {
            int seconds = scoreMiliSeconds / 1000;
            String res = "";

            for (int i = seconds.ToString().Length; i < 6; i++)
            {
                res += "0";
            }

            return res + seconds;
        }


    }

    public class Text
    {
        private String _txt;

        public Text(String txt)
        {
            _txt = txt;
        }

        public Vector2 GetSize(SpriteFont font)
        {
            return font.MeasureString(_txt);
        }

        public Vector2 GetMiddleOrigine(SpriteFont font)
        {
            return new Vector2(GetSize(font).X / 2, GetSize(font).Y / 2);
        }

        public String toString()
        {
            return _txt;
        }
    }
}